import socket, config, os, json, hashlib
import time


class FTPClient(object):
    """
    FTP客户端
    """
    size = 0
    trans_size = 0
    def __init__(self):
        """
        初始化FTP客户端，创建套接字对象
        """
        self.clientSocket = socket.socket()
        self.client_base_url = os.getcwd()+"\\user\\"
        # self.host_ip,self.host_port = self.getsockname()

    def connect(self, ip, port):
        """
        与服务器端建立连接
        :param ip: 服务器ip地址
        :param port: 服务器端口
        :return:
        """
        try:
            self.clientSocket.connect((ip, port))
        except Exception as e:
            print("连接失败：", e)

    def exe_cmd(self, cmd: str):
        """
        根据输入的指令执行操作
        :param cmd: 输入的指令
        :return:
        """
        command = cmd.split()[0]
        if hasattr(self, "%s" % command):
            func = getattr(self, "%s" % command)
            func(cmd)
        else:
            print("非法指令")

    def put(self, *args):
        """
        上传文件
        :param args:绝对路径
        :return:
        """
        file_abs_path = args[0].split()[1]
        # file_abs_path = os.getcwd() + "//user//" + filename
        if os.path.isfile(file_abs_path):
            filesize = os.stat(file_abs_path).st_size
            message = {
                'filepath': file_abs_path,
                'size': filesize,
                'command': args[0].split()[0],
                'action': 'put'
            }
            # encode方法只能编码字符串对象，所以必须使用json传递数据
            self.clientSocket.send(json.dumps(message).encode('utf-8'))
            # 服务端接收到message后准备缓冲区等信息，准备完成后告知客户端
            server_response = self.clientSocket.recv(1024)
            print("-----file upload start-----", server_response)
            # 尝试找到应该开始传输的点
            try:
                start_pos = int(server_response.decode("utf-8").split()[-1])
            except Exception as e:
                print(f"-----can't find start position, {e}-----")
                return
            client_file_size = 0
            if start_pos == 0:
                file = open(file_abs_path, 'rb')
                put_start_time = time.time()
                for line in file:
                    # 发送文件并计算上传的文件的大小
                    client_file_size += self.clientSocket.send(line)
            else:
                # 断点续传，使用seek方法
                with open(file_abs_path, 'rb') as f:
                    put_start_time = time.time()
                    f.seek(start_pos)
                    while start_pos < filesize:
                        data = f.read(1024)
                        self.clientSocket.sendall(data)
                        start_pos += len(data)
                        self.trans_size = round(start_pos * 100 / filesize,4)

            put_end_time = time.time()
            print("transportation time cost: ", put_end_time - put_start_time)
            print("file size: ", client_file_size)
            print('-----file upload end-----')
        else:
            print(f"file {file_abs_path} not exists")

    def get(self, *args):
        """
        下载文件
        :param args:
        :return:
        """
        file_abs_path = args[0].split()[1]
        filename = file_abs_path.split("\\")[-1]
        message = {
            "filepath": file_abs_path,
            "size": "",
            "action": "get",
            "exists": ""
        }
        self.clientSocket.send(json.dumps(message).encode("utf-8"))
        server_response = self.clientSocket.recv(1024)
        fileInfo = json.loads(server_response.decode("utf-8"))
        print(fileInfo)
        exists_in_client_path = os.path.exists(self.client_base_url+filename)
        server_file_size = 0
        start_pos = 0
        if fileInfo["file_exists"]:
            if exists_in_client_path:
                exists_filesize = os.path.getsize(self.client_base_url+filename)
                if exists_filesize == fileInfo["filesize"]:
                    print("-----文件已存在，生成备份文件-----")
                    file = open(self.client_base_url+"_"+filename, "wb")
                    server_file_size = exists_filesize
                else:
                    print("-----断点续传-----")
                    start_pos = exists_filesize
                    file = open(self.client_base_url+filename, "ab")
            else:
                file = open(self.client_base_url+filename, "wb")
            respon_info = f"start at {start_pos}".encode("utf-8")
            self.clientSocket.send(respon_info)
            filesize = fileInfo["filesize"]
            while server_file_size < filesize:
                data = self.clientSocket.recv(1024)
                file.write(data)
                server_file_size += len(data)
                self.trans_size = round(server_file_size * 100 / filesize, 4)

            print("-----download completed------")
            file.close()
        else:
            print(f"-----{filename} not exists------")

    def login(self, user_name: str, password: str):
        """
        尝试登录
        :param user_name:
        :param password:
        :return:
        """
        m = hashlib.md5()
        user_name_list = "".join(user_name.split())
        password_list = "".join(password.split())
        m = hashlib.md5()
        m.update(user_name_list.encode("utf-8"))
        m.update(password_list.encode("utf-8"))
        # md5加密结果
        cryp = m.hexdigest()
        login_info={
            'user_name': user_name,
            'cryp': cryp
        }
        # 登录信息发送给服务端
        self.clientSocket.send(json.dumps(login_info).encode("utf-8"))
        # 接收服务端确认信息
        login_res = self.clientSocket.recv(1024).decode("utf-8")
        if login_res == '1':
            self.clientSocket.send(b'client ready')
            return True
        else:
            return False

def initClient():
    """
    初始化客户端并建立连接
    :return:
    """
    client = FTPClient()
    server_ip = config.get_server_ip()
    server_port = config.get_server_port()
    client.connect(server_ip, server_port)
    if client.login("1940153978", "ztc020517517ztc"):
        print(f"------welcome! 1940153978------")
        client.get("get E:\\FTP\\server\\video.mp4")
    else:
        print("-----login failed!-----")

# initClient()

